package cn.mrcode.smartPluginSecurity.aspect;

import cn.mrcode.smartFramework.annotation.Aspect;
import cn.mrcode.smartFramework.annotation.Controller;
import cn.mrcode.smartFramework.proxy.AspectProxy;
import cn.mrcode.smartPluginSecurity.annotation.User;
import cn.mrcode.smartPluginSecurity.exception.AuthzException;
import org.apache.shiro.SecurityUtils;
import org.apache.shiro.subject.PrincipalCollection;
import org.apache.shiro.subject.Subject;

import java.lang.annotation.Annotation;
import java.lang.reflect.Method;

/**
 * 授权注解切面
 * @author zhuqiang
 * @version V1.0
 * @date 2015/11/21 16:43
 */
@Aspect(Controller.class) //对controller注解的类进行拦截增强
public class AuthzAnnotationAspect extends AspectProxy {
    // 定义基于授权功能的注解类数组
    private static final Class[] ANNOTATION_CLASS_ARRAY = {
        User.class
    };
    @Override
    public void before(Class<?> cls, Method method, Object[] params) throws Throwable {
        Annotation annotation = getAnnotation(cls, method);
        if(annotation != null){
            Class<? extends Annotation> annotationType = annotation.annotationType();
            if(annotationType.equals(User.class)){
                handleUser();
            }
        }
        super.before(cls, method, params);
    }

    /**
     * 从目标方法中获取相应的注解
     * @param cls
     * @param method
     * @return
     */
    private Annotation getAnnotation(Class<?> cls, Method method){
        // 不过这个处理，我在担心，如果这个方法上有多个注解的话，是否就包含更复杂的判断规则了，比如组合同时存在某种角色？
        for (Class annotationClass : ANNOTATION_CLASS_ARRAY) {
            // 目标方法是否带有授权注解
            if(method.isAnnotationPresent(annotationClass)){
                return method.getAnnotation(annotationClass);
            }
            //目标类上是否带有授权注解
            if(cls.isAnnotationPresent(annotationClass)){
                return cls.getAnnotation(annotationClass);
            }
        }
        return null; //都没有则返回空
    }

    private void handleUser() {
        Subject subject = SecurityUtils.getSubject();
        PrincipalCollection principals = subject.getPrincipals(); //还是利用shiro框架提供的功能来判断用户是否登录
        if(principals == null || principals.isEmpty()){
            throw new AuthzException("当前用户未登录");
        }
    }
}
